// 现代 JavaScript 不可变性和函数式数组方法
// 作者：AI助手
// 最后更新：2024年

/**
 * 不可变性是函数式编程的核心原则
 * 特点：
 * 1. 不直接修改数据，而是创建新的数据
 * 2. 使用函数式数组方法
 * 3. 使用展开运算符和 Object.assign
 * 4. 使用不可变数据结构
 */

// 1. 基本不可变性示例
// 1.1 数组操作
const numbers = [1, 2, 3, 4, 5];

// 非不可变操作
function addItem(array, item) {
    array.push(item); // 修改原数组
    return array;
}

// 不可变操作
function immutableAddItem(array, item) {
    return [...array, item]; // 返回新数组
}

// 1.2 对象操作
const user = {
    name: '张三',
    age: 25,
    address: {
        city: '北京',
        street: '长安街'
    }
};

// 非不可变操作
function updateUser(user, newAge) {
    user.age = newAge; // 直接修改对象
    return user;
}

// 不可变操作
function immutableUpdateUser(user, newAge) {
    return {
        ...user,
        age: newAge
    };
}

// 2. 函数式数组方法
// 2.1 map - 转换数组
const doubled = numbers.map(n => n * 2);
console.log('翻倍后的数组:', doubled);

// 2.2 filter - 过滤数组
const evens = numbers.filter(n => n % 2 === 0);
console.log('偶数:', evens);

// 2.3 reduce - 累积操作
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log('总和:', sum);

// 2.4 find - 查找元素
const firstEven = numbers.find(n => n % 2 === 0);
console.log('第一个偶数:', firstEven);

// 2.5 some/every - 条件检查
const hasEven = numbers.some(n => n % 2 === 0);
const allEven = numbers.every(n => n % 2 === 0);
console.log('有偶数:', hasEven, '都是偶数:', allEven);

// 3. 实际应用示例
// 3.1 购物车操作
const cart = [
    { id: 1, name: '手机', price: 5999, quantity: 1 },
    { id: 2, name: '耳机', price: 299, quantity: 2 }
];

// 添加商品（不可变）
function addToCart(cart, item) {
    const existingItem = cart.find(i => i.id === item.id);
    if (existingItem) {
        return cart.map(i =>
            i.id === item.id
                ? { ...i, quantity: i.quantity + item.quantity }
                : i
        );
    }
    return [...cart, item];
}

// 更新数量（不可变）
function updateQuantity(cart, itemId, newQuantity) {
    return cart.map(item =>
        item.id === itemId
            ? { ...item, quantity: newQuantity }
            : item
    );
}

// 移除商品（不可变）
function removeFromCart(cart, itemId) {
    return cart.filter(item => item.id !== itemId);
}

// 3.2 用户状态管理
const initialState = {
    users: [],
    loading: false,
    error: null
};

// 不可变状态更新
function userReducer(state = initialState, action) {
    switch (action.type) {
        case 'FETCH_USERS_START':
            return {
                ...state,
                loading: true,
                error: null
            };
        case 'FETCH_USERS_SUCCESS':
            return {
                ...state,
                loading: false,
                users: action.payload
            };
        case 'FETCH_USERS_ERROR':
            return {
                ...state,
                loading: false,
                error: action.payload
            };
        case 'UPDATE_USER':
            return {
                ...state,
                users: state.users.map(user =>
                    user.id === action.payload.id
                        ? { ...user, ...action.payload }
                        : user
                )
            };
        default:
            return state;
    }
}

// 4. 不可变数据结构
// 4.1 嵌套对象更新
function updateNestedObject(obj, path, value) {
    const [first, ...rest] = path;
    if (rest.length === 0) {
        return { ...obj, [first]: value };
    }
    return {
        ...obj,
        [first]: updateNestedObject(obj[first] || {}, rest, value)
    };
}

// 4.2 不可变数组操作
const immutableArray = {
    push: (array, item) => [...array, item],
    pop: array => array.slice(0, -1),
    shift: array => array.slice(1),
    unshift: (array, item) => [item, ...array],
    splice: (array, start, deleteCount, ...items) => [
        ...array.slice(0, start),
        ...items,
        ...array.slice(start + deleteCount)
    ]
};

// 5. 最佳实践
// ✅ 使用函数式方法处理数组
const processedNumbers = numbers
    .filter(n => n > 2)
    .map(n => n * 3)
    .reduce((sum, n) => sum + n, 0);

// ✅ 使用展开运算符创建新对象
const updatedUser = {
    ...user,
    age: 26,
    address: {
        ...user.address,
        street: '王府井'
    }
};

// ✅ 使用 Object.assign 合并对象
const defaults = { theme: 'light', fontSize: 14 };
const userPrefs = { fontSize: 16 };
const merged = Object.assign({}, defaults, userPrefs);

// ❌ 避免直接修改对象
// function badUpdate(obj) {
//     obj.updated = true; // 直接修改
//     return obj;
// }

// ❌ 避免使用会修改原数组的方法
// const badArray = [1, 2, 3];
// badArray.push(4); // 直接修改
// badArray.sort(); // 直接修改

// 6. 使用示例
// 6.1 购物车操作示例
const newCart = addToCart(cart, { id: 3, name: '充电器', price: 99, quantity: 1 });
console.log('添加商品后的购物车:', newCart);

const updatedCart = updateQuantity(newCart, 2, 3);
console.log('更新数量后的购物车:', updatedCart);

const finalCart = removeFromCart(updatedCart, 1);
console.log('移除商品后的购物车:', finalCart);

// 6.2 嵌套对象更新示例
const complexObject = {
    user: {
        profile: {
            name: '张三',
            settings: {
                theme: 'dark'
            }
        }
    }
};

const updatedComplex = updateNestedObject(
    complexObject,
    ['user', 'profile', 'settings', 'theme'],
    'light'
);
console.log('更新后的嵌套对象:', updatedComplex);

// 6.3 不可变数组操作示例
const originalArray = [1, 2, 3];
const newArray = immutableArray.push(originalArray, 4);
console.log('原始数组:', originalArray);
console.log('新数组:', newArray); 